package com.example.service_order.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.common.commonsutils.DateFormatUtils;
import com.example.common.exception.GuliException;
import com.example.service_order.config.WXConfig;
import com.example.service_order.entity.Order;
import com.example.service_order.entity.PayLog;
import com.example.service_order.mapper.OrderMapper;
import com.example.service_order.mapper.PayLogMapper;
import com.example.service_order.service.PayLogService;
import com.example.service_order.utils.OrderConstUtils;
import com.wechat.pay.java.core.Config;
import com.wechat.pay.java.core.exception.ServiceException;
import com.wechat.pay.java.service.payments.model.Transaction;
import com.wechat.pay.java.service.payments.nativepay.NativePayService;
import com.wechat.pay.java.service.payments.nativepay.model.*;
import jakarta.annotation.Resource;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @Author:tjf
 * @Description:
 */
@Service
public class PayLogServiceImpl extends ServiceImpl<PayLogMapper, PayLog> implements PayLogService {
    @Resource
    private OrderMapper orderMapper;
    @Resource(name = "stringRedisTemplate")
    private StringRedisTemplate redisTemplate;
    @Resource
    private NativePayService nativePayService;
    @Resource
    private WXConfig wxConfig;
    @Resource
    private PayLogMapper payLogMapper;
    /**
     * 获取微信支付二维码
     *
     * @param orderNo
     * @return
     */
    @Override
    public Map<String, Object> createNative(String orderNo) {
        String key = OrderConstUtils.WX_CODE_URL_KEY + orderNo;

        // 查询订单信息
        LambdaQueryWrapper<Order> wrapper = new LambdaQueryWrapper();
        wrapper.eq(Order::getOrderNo, orderNo);
        Order order = orderMapper.selectOne(wrapper);

        if (order == null){
            throw new GuliException(20001, "订单不存在");
        }
        // 已支付过了？
        if (OrderConstUtils.ORDER_PAID == order.getStatus()){
            throw new GuliException(20001, "订单已支付");
        }

        Map map = new HashMap();
        map.put("out_trade_no", orderNo);
        map.put("course_id", order.getCourseId());
        map.put("total_fee", order.getTotalFee());

        // redis中有该订单号对应的支付二维码？
        Boolean codeNotExpire = redisTemplate.hasKey(key);

        if (codeNotExpire == true){
            map.put("code_url", redisTemplate.opsForValue().get(key));
            return map;
        }

        // 获取支付二维码
        try {
            PrepayRequest request = new PrepayRequest();
            Amount amount = new Amount();
            // 0.01
            amount.setTotal(1);
            request.setAmount(amount);
            request.setAppid(wxConfig.getAppid());
            request.setMchid(wxConfig.getMchId());
            request.setDescription("测试商品标题");
            request.setNotifyUrl(wxConfig.getNotifyDomain());
            request.setOutTradeNo(orderNo);
            // 调用下单方法，得到应答
            PrepayResponse response = nativePayService.prepay(request);
            String codeUrl = response.getCodeUrl();

            //最终返回数据 的封装
            map.put("code_url", codeUrl);//二维码地址

            // 把微信支付二维码保存到redis
            redisTemplate.opsForValue().set(key, codeUrl, 20, TimeUnit.MINUTES);
            return map;
        } catch (Exception e) {
            throw new GuliException(20001, "获取微信支付二维码失败");
        }
    }

    /**
     * 查询微信支付的交易状态
     * @param orderNo
     * @return
     */
    @Transactional
    @Override
    public String queryWxPayStatus(String orderNo) {
        // 到数据库查是否已经付款
        LambdaQueryWrapper<Order> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Order::getOrderNo, orderNo);
        Order order = orderMapper.selectOne(wrapper);
        if (order == null){
            throw new GuliException(20001, "订单不存在！");
        }
        if (order != null && order.getStatus() == OrderConstUtils.ORDER_PAID){
            return "SUCCESS";
        }

        //请求wx
        Map<String, Object> map = queryPayStatus(orderNo);
        if (map == null){
            return "";
        }
        String successTime = (String) map.get("successTime");
        String transactionId = (String) map.get("transactionId");
        String tradeState = (String) map.get("tradeState");
        // 支付成功
        if ("SUCCESS".equals(tradeState)){
            // 更新Order对象信息并增加支付日志记录
            order.setStatus(OrderConstUtils.ORDER_PAID);
            order.setPayType(OrderConstUtils.PAY_BY_WX);

            // 更新order记录
            orderMapper.updateById(order);

            // 增加支付记录
            PayLog payLog = new PayLog();
            payLog.setOrderNo(orderNo);
            payLog.setPayType(OrderConstUtils.PAY_BY_WX);
            payLog.setTotalFee(order.getTotalFee());
            payLog.setTransactionId(transactionId);
            payLog.setTradeState(tradeState);
            try {
                Date successDate = DateFormatUtils.getUlogTimestamp(successTime);
                payLog.setPayTime(successDate);
                payLogMapper.insert(payLog);
                // 删除redis中的key
                redisTemplate.delete(OrderConstUtils.WX_CODE_URL_KEY + orderNo);
                redisTemplate.delete(OrderConstUtils.ORDER_KEY + order.getCourseId()
                        + ":" + order.getMemberId());// 存放二维码的
                return "SUCCESS";
            } catch (ParseException e) {
                throw new RuntimeException(e);
            }
        }
        return "";
    }

    /**
     * 查询支付状态
     * @param orderNo
     * @return
     */
    private Map<String, Object> queryPayStatus(String orderNo) {
        QueryOrderByOutTradeNoRequest request = new QueryOrderByOutTradeNoRequest();
        request.setMchid(wxConfig.getMchId());
        request.setOutTradeNo(orderNo);

        try {
            Transaction result = nativePayService.queryOrderByOutTradeNo(request);
            Map<String, Object> map = new HashMap<>();
            map.put("successTime", result.getSuccessTime());
            map.put("transactionId", result.getTransactionId());
            map.put("tradeState", result.getTradeState().name());
            return map;
        } catch (ServiceException e) {
            System.out.printf("code=[%s], message=[%s]\n", e.getErrorCode(), e.getErrorMessage());
            System.out.printf("reponse body=[%s]\n", e.getResponseBody());
            throw new GuliException(20001, e.getErrorMessage());
        }
    }
}
